#include "../chance.hpp"
#include <vector>
#include <iostream>
#include <time.h>

using namespace std;
using namespace gen;

/// Memory object

struct data {
	string name;
	string type;
};

struct table {
	string name;
	vector<data> attributs;
};

/// getter

struct data_range : range< vector<data>::const_iterator > {	
	data_range(table const& me)
	: self_t(me.attributs.begin(), me.attributs.end())
	{}
};

struct table_range : range< vector<table>::const_iterator > {	
	table_range(vector<table> const& me)
	: self_t(me.begin(), me.end())
	{}
};

struct NameFormatter {
	const char * operator()(vector<table>::const_iterator ite) const
	{
		return ite->name.c_str();
	}	
};

struct DataFormatter {
	const char * operator()(vector<data>::const_iterator ite) const
	{
		return ite->name.c_str();
	}
};

struct TypeFormatter {
	const char * operator()(vector<data>::const_iterator ite) const
	{
		return ite->type.c_str();
	}
};

struct ConditionalBranching {
	bool operator()(vector<table>::const_iterator ite) const
	{
		return false;
	}
};

/// My SQL Format file

struct MySQLGenerator : public report<MySQLGenerator> {

	template <typename InfoT>
	struct etat {
		NameFormatter NameFormat;
		DataFormatter DataFormat;
		TypeFormatter TypeFormat;
		ConditionalBranching IsComment;

		//typedef limit<InfoT,data_range>			data_limit;
		typedef limit_n<InfoT,1>				table_limit;
		typedef typename table_limit::info_t	table_info;

		typedef limit_n<table_info,2>			data_limit;
		typedef typename data_limit::info_t		data_info;

		format<InfoT>		ScriptSQL;
		format<table_info>	CreateTable;
		format<data_info>	CreateAttribut;

		etat(MySQLGenerator const& me) 
		{
            data_limit data0(data_limit::beg);
			data_limit dataN(data_limit::end);

            table_limit table0(table_limit::beg);
			table_limit tableN(table_limit::end);

			ScriptSQL = 
				( CreateTable << '\n' )	[table0, tableN]; ;
			
			CreateTable = 
				str_g("CREATE TABLE ") << act_g(NameFormat) << '('
					<< ( '\t' << CreateAttribut << ",\n\t\t" )		[data0, dataN-1]
					<< ( '\t' << CreateAttribut )					[dataN-1, dataN]
					<< ( ch_g('\t') << "-- un commentaire :)\n" )	[if_g(IsComment)] 
				<< ");\n\n" ;

			CreateAttribut = 
				act_g(DataFormat) << ' ' << act_g(TypeFormat) ;
		}

		format<InfoT> const& start() const { return ScriptSQL; }
    };
};

/// test program

int main(){
	vector<table> database;
	table person, company;
	data tel, address;

	person.name = "personne";
	tel.name = "telephone";
	tel.type = "string";
	address.name = "adresse";
	address.type = "text";
	person.attributs.push_back(tel);
	person.attributs.push_back(address);

	company.name = "company";
	company.attributs.push_back(tel);
	company.attributs.push_back(address);

	database.push_back(person);
	database.push_back(company);

	MySQLGenerator sql_g;


	//wstring out = generate<wchar_t, data_range>(database.begin(), database.end(), sql_g);
	//wstring out = generate<wchar_t>(database.begin(), database.end(), sql_g);
	//std::wcout << out;
	
	//string out = generate<char,data_range>(database.begin(), database.end(), sql_g);
	clock_t t0 = clock();
	string out = generate<char,table_range,data_range>(wrap_g(database) , sql_g);
	std::cout << out;
    
	clock_t t1 = clock();
	std::cout << endl << " : " << t1-t0 << endl;

	t0 = clock();
	for(int i=0; i<database.size(); i++){
		cout << "CREATE TABLE " << database[i].name << '(';
		for (int j=0; j<database[i].attributs.size(); j++) {
			cout << database[i].attributs[j].name << ' ' << database[i].attributs[j].type;
			cout << ",\n\t\t";
		}
		cout << '\n';
	}
	
	t1 = clock();
	std::cout << endl << " : " << t1-t0 << endl;

	system("pause");
}
